# -*- coding:utf-8 -*-

# @File     :query_tree
# @Author   :Yupeng
# @Date     :2018/11/12 17:16
'''
搜索最好是将独立数据的搜索与数据集的搜索分开
数据集的搜索只按照元数据来搜
独立数据的搜索目前也只按照元数据进行
***
在搜索框内填写搜索信息之后，都是按包含关系处理的
'''
from django.utils.translation import ugettext as _

from treelib.exceptions import NodeIDAbsentError
from treelib import Tree, Node
from elasticsearch_dsl import Search

from apps.storage.models.template import Template
from apps.storage.models.data import DataMeta
from apps.storage.models.template import TemplateField
# from apps.search.core.
from hte.error.models import HTEError, HTEException
from .operator import DataOperator
from .es_handler import Transform, ES_QUERY_MAX_SIZE

from enum import IntEnum, Enum
from typing import *
import json


class QuerySortField(Enum):
    '''
    已经点击搜索之后对结果的排序或者筛选字段
    '''
    # 数据集的元数据字段
    DATASET_UPLOAD_TIME = 'ds-upload-time'  # 数据集的上传时间
    # DATASET_SUPERVISE = 'ds-supervise'  # 是否为有监督的数据集，暂时还没有该字段
    # DATASET_ROWS = 'ds-rows'  # 数据集的条数(行数)升序或者降序排列
    DATASET_UPDATE_TIME = 'ds-update-time'  # 数据集的修改时间
    DATASET_REF_COUNT = 'ds-ref-count'  # 数据集的引用次数

    # 单条数据的元数据字段
    DATA_CREATED_TIME = "d-time"  # 按上传时间排序（升序或者降序）。或者直接选择上传的提起，在该情况下，最好是做成时间选择模块，不要让用户输入
    NO_SORTING = ''

    @property
    def is_data_meta_field(self):
        return self == QuerySortField.DATA_CREATED_TIME

    @property
    def is_dataset_field(self):
        return not self.is_data_meta_field

    @property
    def sql_name(self):
        if self == QuerySortField.DATA_CREATED_TIME:
            return 'add_time'
        elif self == QuerySortField.DATASET_UPLOAD_TIME:
            return "upload_time"
        elif self == QuerySortField.DATASET_UPDATE_TIME:
            return 'update_time'
        else:
            return 'ref_count'


class QuickSimpleFullTextQuery:
    '''
    简单全文检索
    '''

    def __init__(self, dataset: bool, query_string: str):
        self._query_string = query_string.strip()  # 去除字符串首末空格
        self._dataset = dataset

    def to_dict(self):
        '''
        将查询的字符串转换为ES能够识别的dict
        :return:
        '''
        query_phrases = []  # 查询短语列表
        query_phrase = ''  # 查询短语
        pre_quotes = False  # 引号
        parsed_query_phrase = False  # 是否为已经解析的查询短语
        for c in self._query_string:
            if pre_quotes:
                if c in ('\"', '\“', '\”'):
                    if len(query_phrase) > 0:
                        parsed_query_phrase = True
                    pre_quotes = None  # False?
                else:
                    query_phrase += c
            else:
                if c in (' ', '\t', '\n', '\"', '\“', '\”'):
                    if len(query_phrase) > 0:
                        parsed_query_phrase = True
                else:
                    query_phrase += c
                if c in ('\"', '\“', '\”'):
                    pre_quotes = True

            if parsed_query_phrase:
                query_phrases.append(query_phrase)
                parsed_query_phrase = False
                query_phrase = ''

        if len(query_phrase) > 0:
            query_phrases.append(query_phrase)

        ret = []
        for query_phrase in query_phrases:
            ret.append(Transform.match_phrase_dic('_data', query_phrase))
        return Transform.query_dic(Transform.bool_dic(must=ret))

    def query(self):

        dsl = self.to_dict()

        if not self._dataset:  # 如果不是数据集的查询
            dsl['_source'] = '_meta_id'
            q = Search.from_dict(dsl)
            q._index = ['data_snapshot']
            q.update_from_dict({'size': min(q.count(), ES_QUERY_MAX_SIZE)})

            ret = list()  # ret==return
            for item in q.execute():
                ret.append(item['_meta_id'])
        else:
            dsl['_source'] = '_dataset_id'
            q = Search.from_dict(dsl)
            q._index = ['dataset_snapshot']
            q.update_from_dict({'size': min(q.count(), ES_QUERY_MAX_SIZE)})

            ret = list()  # ret==return
            for item in q.execute():
                ret.append(item['_dataset_id'])
        return ret


class MetaQuery:
    '''
    元数据检索，限制搜索框内输入的信息只在选定的元数据字段内搜索
    '''

    def __init__(self, dataset: bool, metadata: str, text: str):
        self._metadata = metadata  # 元数据字段
        self._text = text.strip()  # 搜索框内的信息，strip()去除字符串首末空格
        self._dataset = dataset

    def to_dict(self):
        '''
        将查询的字符串转换为ES能够识别的dict
        :return:
        '''
        query_phrases = []  # 查询短语列表
        query_phrase = ''  # 查询短语
        pre_quotes = False  # 引号
        parsed_query_phrase = False  # 是否为已经解析的查询短语
        for c in self._text:
            if pre_quotes:
                if c in ('\"', '\“', '\”'):
                    if len(query_phrase) > 0:
                        parsed_query_phrase = True
                    pre_quotes = None  # False?
                else:
                    query_phrase += c
            else:
                if c in (' ', '\t', '\n', '\"', '\“', '\”'):
                    if len(query_phrase) > 0:
                        parsed_query_phrase = True
                else:
                    query_phrase += c
                if c in ('\"', '\“', '\”'):
                    pre_quotes = True

            if parsed_query_phrase:
                query_phrases.append(query_phrase)
                parsed_query_phrase = False
                query_phrase = ''

        if len(query_phrase) > 0:
            query_phrases.append(query_phrase)

        ret = []
        # if not self._dataset:
        ret.append(Transform.term_dic('p.key.keyword', self._metadata))
        for query_phrase in query_phrases:
            if self._metadata == 'keywords':
                ret.append(Transform.nested_dic('p.list', Transform.query_dic(Transform.match_phrase_dic('p.list.text', query_phrase))))
            else:
                ret.append(Transform.match_phrase_dic('p.text', query_phrase))

        return Transform.query_dic(Transform.nested_dic('p', Transform.bool_dic(must=ret)))
        # else:
        #     ret.append(Transform.term_dic('p.key.keyword', self._metadata))
        #     for query_phrase in query_phrases:
        #         if self._metadata == 'keywords':
        #             ret.append(Transform.match_phrase_dic('p.text', query_phrase))
        #         else:
        #             ret.append(Transform.match_phrase_dic('p.'))
        #
        #     return Transform.query_dic(Transform.bool_dic(must=ret))
        # return Transform.query_dic(Transform.bool_dic(must=ret))

    def query(self):
        dsl = self.to_dict()

        if not self._dataset:
            dsl['_source'] = '_meta_id'
            q = Search.from_dict(dsl)
            q._index = ['data_meta']
            q.update_from_dict({'size': min(q.count(), ES_QUERY_MAX_SIZE)})
            ret = list()  # ret==return
            for item in q.execute():
                ret.append(item['_meta_id'])
        else:
            dsl['_source'] = '_dataset_id'
            q = Search.from_dict(dsl)
            q._index = ['dataset_meta']
            q.update_from_dict({'size': min(q.count(), ES_QUERY_MAX_SIZE)})
            ret = list()  # ret==return
            for item in q.execute():
                ret.append(item['_dataset_id'])
        return ret
